using System;

using System.Data;
using System.Linq.Expressions;
using NUnit.Framework;
using ServiceStack.DataAnnotations;
using ServiceStack.Model;

namespace ServiceStack.OrmLite.MySql.Tests.Expressions;

[TestFixture]
public class OrmLiteCountTests : OrmLiteTestBase
{
    [Test]
    public void CanDoCountWithInterface()
    {
        using (var db = OpenDbConnection())
        {
            db.CreateTable<CountTestTable>(true);
            db.DeleteAll<CountTestTable>();

            db.Insert(new CountTestTable { Id = 1, StringValue = "Your string value" });

            var count = db.Scalar<CountTestTable, long>(e => Sql.Count(e.Id));

            Assert.That(count, Is.EqualTo(1));

            count = Count<CountTestTable>(db);

            Assert.That(count, Is.EqualTo(1));

            count = CountByColumn<CountTestTable>(db);

            Assert.That(count, Is.EqualTo(0));

        }
    }

    [Test]
    public void CanDoCountWithInterfaceAndPredicate()
    {
        using (var db = OpenDbConnection())
        {
            db.CreateTable<CountTestTable>(true);
            db.DeleteAll<CountTestTable>();
            db.Insert(new CountTestTable { Id = 1, StringValue = "Your string value" });

            Expression<Func<CountTestTable, bool>> exp = q => q.Id == 2;
            var count = Count(db, exp);
            Assert.That(count, Is.EqualTo(0));


            exp = q => q.Id == 1;
            count = Count(db, exp);
            Assert.That(count, Is.EqualTo(1));

            exp = q => q.CountColumn == null;
            count = Count(db, exp);
            Assert.That(count, Is.EqualTo(1));

            exp = q => q.CountColumn == null;
            count = CountByColumn(db, exp);
            Assert.That(count, Is.EqualTo(0));
        }
    }

    long Count<T>(IDbConnection db) where T : IHasId<int>
    {
        return db.Scalar<T, long>(e => Sql.Count(e.Id));
    }


    long CountByColumn<T>(IDbConnection db) where T : IHasCountColumn
    {
        return db.Scalar<T, long?>(e => Sql.Count(e.CountColumn)).Value;
    }


    int Count<T>(IDbConnection db, Expression<Func<T, bool>> predicate) where T : IHasId<int>
    {
        return db.Scalar<T, int>(e => Sql.Count(e.Id), predicate);
    }

    int CountByColumn<T>(IDbConnection db, Expression<Func<T, bool>> predicate) where T : IHasCountColumn
    {
        return db.Scalar<T, int?>(e => Sql.Count(e.CountColumn), predicate).Value;
    }

}

public interface IHasCountColumn
{
    int? CountColumn { get; set; }
}


public class CountTestTable : IHasId<int>, IHasCountColumn
{
    public CountTestTable() { }
    #region IHasId implementation
    public int Id { get; set; }
    [StringLength(40)]
    public string StringValue { get; set; }
    #endregion

    #region IHasCountColumn implementation
    public int? CountColumn { get; set; }
    #endregion
}